package cn.kgc.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import cn.kgc.base.BaseInfoProperties;
import cn.kgc.base.SystemConstant;
import cn.kgc.entity.Resume;
import cn.kgc.entity.SysParams;
import cn.kgc.excpetion.GraceException;
import cn.kgc.feign.ResumeFeignClient;
import cn.kgc.grace.result.GraceJSONResult;
import cn.kgc.grace.result.ResponseStatusEnum;
import cn.kgc.mapper.SysParamsMapper;
import cn.kgc.service.ResumeService;
import cn.kgc.service.SysParamsService;
import cn.kgc.utils.RedisUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.benmanes.caffeine.cache.Cache;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;


/**
 * @author YC
 */
@Slf4j
@Service("sysParamsService")
public class SysParamsServiceImpl extends ServiceImpl<SysParamsMapper, SysParams> implements SysParamsService {

    @Resource
    private RedisUtil redisUtil;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private Cache<String, Object> refreshResumeCountCache;

    @Override
    public Object getRefreshMaxCount() {
        String key = BaseInfoProperties.REDIS_MAX_RESUME_REFRESH_COUNTS;
        // 先从本地缓存中拿
        Object cacheValue = refreshResumeCountCache.getIfPresent(key);
        if (cacheValue != null) {
            return cacheValue;
        }
        // 本地缓存没有数据再从分布式缓存中获取
        cacheValue = redisUtil.get(key);
        if (cacheValue != null) {
            return cacheValue;
        }
        // 从缓存中获取最大刷新次数
        RLock lock = redissonClient.getLock("maxResumeRefreshCountsLock");
        boolean isLock = false;
        try {
            // 将请求锁定2秒，2秒还没有获得锁，直接返回默认值（每天最大允许刷新次数为5）
            isLock = lock.tryLock(2, 2, TimeUnit.SECONDS);
            if (!isLock) {
                return SystemConstant.MAX_RESUME_REFRESH_COUNTS;
            }
            // 如果请求获得了锁，再次从缓存中获取数据
            cacheValue = redisUtil.get("maxResumeRefreshCounts");
            if (cacheValue != null) {
                return cacheValue;
            }
            // 如果缓存中还是没有数据，从数据库中获取
            List<SysParams> list = this.list();
            if (CollUtil.isEmpty(list)) {
                redisUtil.set("maxResumeRefreshCounts", SystemConstant.MAX_RESUME_REFRESH_COUNTS,
                        SystemConstant.MAX_RESUME_REFRESH_COUNTS_CACHE_TIME, TimeUnit.DAYS);
                return SystemConstant.MAX_RESUME_REFRESH_COUNTS;
            }
            SysParams sysParams = list.get(0);
            redisUtil.set("maxResumeRefreshCounts", sysParams.getMaxResumeRefreshCounts(),
                    SystemConstant.MAX_RESUME_REFRESH_COUNTS_CACHE_TIME, TimeUnit.DAYS);
            return sysParams.getMaxResumeRefreshCounts();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void modifySysParams(int maxCount) {
//        try {
        // 先获得表中数据
        List<SysParams> list = this.list();
        if (list.size() == 1) {
            // 表中有数据，更新表中数据
            SysParams sysParams = list.get(0);
            sysParams.setMaxResumeRefreshCounts(maxCount);
            baseMapper.updateById(sysParams);
        } else {
            // 表中没有数据，新增数据
            SysParams sysParams = new SysParams();
            sysParams.setMaxResumeRefreshCounts(maxCount);
            baseMapper.insert(sysParams);
        }
        // 将最大刷新次数从缓存中删除
        redisUtil.delete("maxResumeRefreshCounts");
        // 使用caffoine缓存，不需要删除了
//        } catch (Exception e) {
        // 将消息发送消息队列中,从消息队列中获得数据在从缓存中删除（延迟双删）
//            redisUtil.delete("maxResumeRefreshCounts");
//        }
    }

    @Resource
    private ResumeService resumeService;
    @Resource
    private ResumeFeignClient resumeFeignClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean refreshResume(String resumeId, String userId) {
        // 判断用户当前简历刷新次数是否超出最大次数
        String key = "REFRESH_RESUME_COUNTS:" + userId + "_" + resumeId;
        int count = redisUtil.get(key) == null ? 0 : Integer.parseInt(redisUtil.get(key).toString());
        int maxRefreshCount = (int) getRefreshMaxCount();
        if (count >= maxRefreshCount) {
            GraceException.display(ResponseStatusEnum.RESUME_MAX_LIMIT_ERROR);
        }
        count++;
        if (count == 1) {
            // 如果用户第一次刷新简历，设置过期时间
            redisUtil.set(key, count, 1, TimeUnit.DAYS);
        } else {
            redisUtil.set(key, count);
        }
        redisUtil.set(key, count, 1, TimeUnit.DAYS);
        // 刷新简历并更新简历的刷新时间
        resumeService.update(new LambdaUpdateWrapper<Resume>()
                .eq(Resume::getId, resumeId)
                .eq(Resume::getUserId, userId)
                .set(Resume::getRefreshTime, new Date())
        );
        // 保存到ES中
        Object data = resumeFeignClient.refreshResume(resumeId, userId).getData();
        GraceJSONResult result = JSONUtil.toBean(JSONUtil.toJsonStr(data), GraceJSONResult.class);
        if (result.getStatus() == 200 || result.getSuccess() == false) {
            GraceException.display(ResponseStatusEnum.RESUME_REFRESH_ES_ERROR);
        }
        return true;
    }

}
